package cn.wolfcode.luowowo.search.service;

import cn.wolfcode.luowowo.search.domain.DestinationTemplate;
import cn.wolfcode.luowowo.search.domain.StrategyTemplate;
import cn.wolfcode.luowowo.search.qo.StrategySearchQuery;
import cn.wolfcode.luowowo.search.repository.StretegySearchRepository;
import cn.wolfcode.luowowo.search.vo.EsStatisVo;
import com.alibaba.dubbo.config.annotation.Service;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.bucket.composite.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.*;

@Service
public class StrategySearchServiceImpl implements IStrategySearchService {
    @Autowired
    private StretegySearchRepository repository;
    @Autowired
    private ElasticsearchTemplate template;
    @Override
    public void saveOrUpdate(StrategyTemplate template) {
        repository.save(template);
    }

    @Override
    public List<Map<String, Object>> queryThemeTop10() {
        List<Map<String, Object>> list = new ArrayList<>();

        //多列查询有一个Composite
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();

        //多列分组
        //id
        TermsValuesSourceBuilder idSources = new TermsValuesSourceBuilder("id");
        idSources.field("themeId");

        //name
        TermsValuesSourceBuilder nameSources = new TermsValuesSourceBuilder("name");
        nameSources.field("themeName");

        sources.add(idSources);
        sources.add(nameSources);

        //参数1:分组查询结果操作名称
        //参数2:分组查询的列对象集合
        CompositeAggregationBuilder aggregationBuilder =
                new CompositeAggregationBuilder("themeGroup",sources);

        //实现相关步骤
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.addAggregation(aggregationBuilder);
        //分页
        builder.withPageable(PageRequest.of(0,1));



        /**
         * 查询结果
         * "aggregations" : {
         *     "themeGroup" : {
         *       "after_key" : {
         *         "id" : 16,
         *         "name" : "家庭"
         *       },
         *       "buckets" : [
         *         {
         *           "key" : {
         *             "id" : 3,
         *             "name" : "户外"
         *           },
         *           "doc_count" : 2
         *         },
         */


        //发送查询语句返回结果
        AggregatedPage<StrategyTemplate> search = ((AggregatedPage) repository.search(builder.build()));
        InternalComposite themeGroup = search.getAggregations().get("themeGroup");
        //这是内部类,用静态修饰的,而这种只能给子类或者是同包下的类使用InternalComposite.InternalBucket
        //List<InternalComposite.InternalBucket> buckets = themeGroup.getBuckets()

        //Map<String,Object> map = new HashMap<>();   如果这样写会全部一样
        Map<String,Object> map = null;
        EsStatisVo vo = null;
        for (CompositeAggregation.Bucket bucket : themeGroup.getBuckets()) {
            Long id = Long.parseLong(bucket.getKey().get("id").toString());
            String name = bucket.getKey().get("name").toString();
            Long count = bucket.getDocCount();
            vo = new EsStatisVo(id,name,count);

            //目的地列表:通过主题id查询目的地集合   1.城市去重
            List<EsStatisVo> dests =  queryDestByThemeId(id);
            map = new HashMap<>();
            map.put("theme",vo);
            map.put("dests",dests);
            list.add(map);
            /**
             * 封装成这种数据给前端
             * {
             * theme:{id,name}
             * dests:List<EsStatisVo> -->{destid,destName},{destid,destName},{destid,destName}
             * }
             */

            //优化: 1.城市重复(去重),2.排序,3.前10个
        }
        //2.排序 按关联目的地的数量多少排序 ,结果int  大的在前面
        Collections.sort(list, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                //用两个map对象的theme对象里的count值去排序,这个值就是有多少个城市
                EsStatisVo vo1 = (EsStatisVo) o1.get("theme");
                EsStatisVo vo2 = (EsStatisVo) o2.get("theme");
                Long ret = vo2.getCount()-vo1.getCount();
                return ret.intValue();
            }
        });

        //3.只需要前10个数据
        if (list.size()>10){
            list = list.subList(0,10);
        }
        return list;
    }

    @Override
    public List<EsStatisVo> queryConditionThemeGroup() {
        return statisVOGroup("themeId","themeName","themeGroup",null);
    }

    @Override
    public List<EsStatisVo> queryConditioncChinasGroup() {
        return  statisVOGroup("provinceId","provinceName","provinceGroup",null);
    }

    @Override
    public List<EsStatisVo> queryConditioncAbroadsGroup() {
        //国外攻略不应该有中国 排除中国  +一个查询条件
        BoolQueryBuilder query = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("countryId", 1));

        return   statisVOGroup("countryId","countryName","countryGroup",query);
    }

    @Override
    public Page query(StrategySearchQuery qo) {

        //按照条件查询
        Pageable pageable = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize(), Sort.Direction.DESC, qo.getOrderBy());
        if (qo.getType() == StrategySearchQuery.CONDITION_TYPE_ABROAD){
            return repository.search(QueryBuilders.termQuery("countryId",qo.getTypeValue()),pageable);
        }
        if (qo.getType() == StrategySearchQuery.CONDITION_TYPE_CHINA){
            return repository.search(QueryBuilders.termQuery("provinceId",qo.getTypeValue()),pageable);
        }

        if (qo.getType() == StrategySearchQuery.CONDITION_TYPE_THEME){
            return repository.search(QueryBuilders.termQuery("themeId",qo.getTypeValue()),pageable);
        }
        //如果啥也不是就查全部
        return repository.findAll(pageable);
    }

    @Override
    public List<StrategyTemplate> findByDestName(String keyword) {
        return repository.findByDestName(keyword);

    }


    private List<EsStatisVo> queryDestByThemeId(Long themeId) {
        List<StrategyTemplate> list = repository.findByThemeId(themeId);
        List<EsStatisVo> esVo = new ArrayList<>();
        //去重操作
        List<String> names= new ArrayList<>();
        //讲查出来的mud地集合封装到EsStatisVo对象中返回
        for (StrategyTemplate template : list) {
            //判断城市集合是否有,如果没有才封装对象
            if (!names.contains(template.getDestName())){
                EsStatisVo esStatisVo = new EsStatisVo();
                esStatisVo.setId(template.getDestId());
                esStatisVo.setName(template.getDestName());
                esVo.add(esStatisVo);
                names.add(template.getDestName());
            }
        }
        return esVo;
    }



    //抽取
    private List<EsStatisVo> statisVOGroup(String idField, String nameField, String groupName,BoolQueryBuilder query) {
        //多列查询有一个Composite
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();

        //多列分组
        //id
        TermsValuesSourceBuilder idSources = new TermsValuesSourceBuilder("id");
        idSources.field(idField);

        //name
        TermsValuesSourceBuilder nameSources = new TermsValuesSourceBuilder("name");
        nameSources.field(nameField);

        sources.add(idSources);
        sources.add(nameSources);

        //参数1:分组查询结果操作名称
        //参数2:分组查询的列对象集合
        CompositeAggregationBuilder aggregationBuilder =
                new CompositeAggregationBuilder(groupName,sources);

        //实现相关步骤
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.addAggregation(aggregationBuilder);
        //分页
        builder.withPageable(PageRequest.of(0,1));

        //查询条件
        if(query != null){
            builder.withQuery(query);
        }
        /**
         * 查询结果
         * "aggregations" : {
         *     "themeGroup" : {
         *       "after_key" : {
         *         "id" : 16,
         *         "name" : "家庭"
         *       },
         *       "buckets" : [
         *         {
         *           "key" : {
         *             "id" : 3,
         *             "name" : "户外"
         *           },
         *           "doc_count" : 2
         *         },
         */

        //发送查询语句返回结果
        AggregatedPage<StrategyTemplate> search = ((AggregatedPage) repository.search(builder.build()));
        InternalComposite themeGroup = search.getAggregations().get(groupName);
        //这是内部类,用静态修饰的,而这种只能给子类或者是同包下的类使用InternalComposite.InternalBucket
        //List<InternalComposite.InternalBucket> buckets = themeGroup.getBuckets()

        List<EsStatisVo> list = new ArrayList<>();
        EsStatisVo vo = null;
        for (CompositeAggregation.Bucket bucket : themeGroup.getBuckets()) {
            Long id = Long.parseLong(bucket.getKey().get("id").toString());
            String name = bucket.getKey().get("name").toString();
            Long count = bucket.getDocCount();
            vo = new EsStatisVo(id,name,count);
            list.add(vo);

        }

        //排序
        Collections.sort(list, new Comparator<EsStatisVo>() {
            @Override
            public int compare(EsStatisVo o1, EsStatisVo o2) {
                Long ret = o2.getCount() - o1.getCount();
                return ret.intValue();
            }
        });

        return list;
    }
}
